package ipc.project;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;

import android.os.Handler;
import android.os.Message;

public class ConnectionWithServer {

	private static String SERVER_IP = "192.168.151.1";
	private static String SERVER_NAME = "@127.0.0.1";

	private XMPPConnection con;
	private Roster roster;
	private String groups[] = { "Freinds" };

	private PacketFilter filter;
	private PacketListener listener;
	private static RosterListener rosterListener;

	private static Set<String> inRequests = new HashSet<String>();
	private static Set<String> outRequests = new HashSet<String>();
	private static Map<String, Friend> onlineFriends = new HashMap<String, Friend>();
	private static Map<String, Friend> offlineFriends = new HashMap<String, Friend>();

	private static Handler freindsHandler = null;
	private static Handler requestsHandler = null;
	public ConnectionWithServer() {
		con = new XMPPConnection(SERVER_IP);
		Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.manual);
	}

	public static void setFriendsHandler(Handler handler) {
		freindsHandler = handler;
	}

	public static void setRequestsHandler(Handler handler) {
		requestsHandler = handler;
	}

	public boolean check() {
		try {
			con.connect();
		} catch (XMPPException e) {
			return false;
		}
		return true;
	}

	public boolean signIn(String login, String password) {
		try {
			con.connect();
			con.login(login, password);
			roster = con.getRoster();
			getFriendsFromServer();
			setListeners();
		} catch (XMPPException e) {
			return false;
		}
		return true;
	}
	public boolean signUp(String login, String password) {
		try {
			con.connect();
			AccountManager manager = new AccountManager(con);
			HashMap<String, String> parameters = new HashMap<String, String>();
			parameters.put("username", login);
			parameters.put("password", password);
			manager.createAccount(login, password, parameters);
			con.login(login, password);
		} catch (XMPPException e) {
			return false;
		}
		return true;
	}

	public void signOut() {
		con.removePacketListener(listener);
		con.disconnect(new Presence(Presence.Type.unavailable));
		roster = null;
		con = null;
	}

	public void setStatus(String status) {
		Presence presence = new Presence(Presence.Type.available);
		presence.setStatus(status);
		con.sendPacket(presence);
	}

	private void getFriendsFromServer(){
		roster=con.getRoster();
		Collection<RosterEntry> entries = roster.getEntries();
		for(RosterEntry entry : entries){
			System.out.println(entry.getUser()+" "+entry.getType());
			if(entry.getType()==ItemType.both){
				offlineFriends.put(entry.getName(), new Friend(entry.getName()));
			}
			else if (entry.getType()==ItemType.to){
				outRequests.add(entry.getUser());
			}
		}
	}
	
	public void sendRequest(String login) {
			sendPresence(login, Presence.Type.subscribe);
	}

	public void acceptRequest(String login) {
		sendRequest(login);
		sendPresence(login, Presence.Type.subscribed);
		sendPresence(login, Presence.Type.available);
	}

	public void declineRequest(String login) {
		String address = login + "@127.0.0.1";
		Presence subscribed = new Presence(Presence.Type.unsubscribe);
		subscribed.setTo(address);
		con.sendPacket(subscribed);
		inRequests.remove(login);
	}

	public static int getCountOfOnlineFriends() {
		return onlineFriends.size();
	}

	public List<Friend> getOnlineFriends() {
		return new ArrayList<Friend>(onlineFriends.values());
	}

	public List<Friend> getFriends() {
		List<Friend> result = getOnlineFriends();
		result.addAll(offlineFriends.values());
		return result;
	}

	public void deleteFriend(String login) {
		try {
			roster.removeEntry(roster.getEntry(login + SERVER_NAME));
		} catch (XMPPException e) {
		}
	}

	public List<String> getInRequests() {
		return new ArrayList<String>(inRequests);
	}

	public List<String> getOutRequests() {
		return new ArrayList<String>(outRequests);
	}

	public void close() {
		roster.removeRosterListener(rosterListener);
		con.removePacketListener(listener);
		con.disconnect();
	}

	public void setListeners() {
		rosterListener = new RosterListener() {
			public void entriesAdded(Collection<String> addresses) {
				System.out.println(addresses);
			}

			public void entriesDeleted(Collection<String> addresses) {
				System.out.println("roster delet");
			}

			public void entriesUpdated(Collection<String> addresses) {
				System.out.println("roster update");
			}

			public void presenceChanged(Presence presence) {
				String address = presence.getFrom();
				String login = Friend.getLoginFromAddress(address);
				if(presence.getType()==Presence.Type.available){
					String status = presence.getStatus();
					setFriendOnline(login,status);
				}
				else if(presence.getType()==Presence.Type.unavailable){
					setFriendOffline(login);
					}
			}
		};
		filter = new PacketFilter() {
			public boolean accept(Packet packet) {
				return true;
			}
		};
		listener = new PacketListener() {
			public void processPacket(Packet packet) {
				Type type = ((Presence) packet).getType();
				System.out.println(packet.getFrom() + ":" + type.toString());
				if (type == Presence.Type.available)
					//addOnliner((Presence) packet);
				if (type == Presence.Type.unavailable)
					//addOffliner((Presence) packet);
				if (type == Presence.Type.subscribe)
					addIncomingRequest((Presence) packet);
			}
		};
		roster.addRosterListener(rosterListener);
		con.addPacketListener(listener, filter);
	}

	public static void addOnliner(Presence presence) {
		String status = presence.getStatus();
		String address = presence.getFrom();
		onlineFriends.put(address, new Friend(address, status));
		offlineFriends.remove(address);
		freindsHandler.sendEmptyMessage(1);
	}

	public static void addOffliner(Presence presence) {
		String status = presence.getStatus();
		String address = presence.getFrom();
		if (onlineFriends.remove(address) != null) {
			offlineFriends.put(address, new Friend(address, status));
		}
		freindsHandler.sendEmptyMessage(1);
	}

	public static void addIncomingRequest(Presence presence) {
		String login = Friend.getLoginFromAddress(presence.getFrom());
		inRequests.add(login);
		requestsHandler.sendEmptyMessage(1);
	}

	public void sendPresence(String toLogin, Type type) {
		String address = toLogin + SERVER_NAME;
		Presence presence = new Presence(type);
		presence.setTo(address);
		con.sendPacket(presence);
	}
	public static void setFriendOnline(String login, String status) {
		onlineFriends.put(login, new Friend(login, status));
		offlineFriends.remove(login);
		freindsHandler.sendEmptyMessage(1);
	}
	public static void setFriendOffline(String login) {
		onlineFriends.remove(login);
		offlineFriends.put(login,new Friend(login));
		freindsHandler.sendEmptyMessage(1);
	}
}